package com.yingdong.gateserver.innter.message;

import java.io.UTFDataFormatException;
import java.util.ArrayList;
import java.util.List;


import com.yingdong.gateserver.opcode.Dispatcher;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;

public class GameMessage {
	public static final int INIT_SIZE = 64;
	private ByteBuf buffer;
	private int opcode;
	private int sessionId;

	private List<Integer> sessionList = new ArrayList<Integer>();

	public List<Integer> getSessionList() {
		return sessionList;
	}

	public void setSessionList(List<Integer> sessionList) {
		this.sessionList = sessionList;
	}

	public int getSessionId() {
		return sessionId;
	}

	public void setSessionId(int sessionId) {
		this.sessionId = sessionId;
	}

	public ByteBuf getBuffer() {
		return buffer;
	}

	public void setBuffer(ByteBuf buffer) {
		this.buffer = buffer;
	}

	public int getOpcode() {
		return opcode;
	}

	public void setOpcode(int opcode) {
		this.opcode = opcode;
	}

	public GameMessage(int opcode, int sessionId) {
		this.opcode = opcode;
		this.sessionId = sessionId;
		buffer = ByteBufAllocator.DEFAULT.buffer(INIT_SIZE);
		buffer.writeInt(opcode);
	}

	public GameMessage(int opcode, int sessionId, ByteBuf buffer) {
		this.opcode = opcode;
		this.buffer = buffer;
		this.sessionId = sessionId;

	}

	public void writeInt(int value) {
		buffer.writeInt(value);

	}

	public void writeShort(int value) {
		buffer.writeShort(value);

	}

	public void writeByte(int value) {
		buffer.writeByte(value);

	}

	public void writeDouble(double value) {
		buffer.writeDouble(value);

	}

	public void writeFloat(float value) {
		buffer.writeFloat(value);

	}

	public void writeLong(int value) {
		buffer.writeLong(value);
	}

	public void writeUTF(String str) throws UTFDataFormatException {
		int strlen = str.length();
		int utflen = 0;
		int c, count = 0;

		/* use charAt instead of copying String to char array */
		for (int i = 0; i < strlen; i++) {
			c = str.charAt(i);
			if ((c >= 0x0001) && (c <= 0x007F)) {
				utflen++;
			} else if (c > 0x07FF) {
				utflen += 3;
			} else {
				utflen += 2;
			}
		}

		if (utflen > 65535)
			throw new UTFDataFormatException("encoded string too long: " + utflen + " bytes");

		byte[] bytearr = null;

		bytearr = new byte[utflen + 2];

		bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
		bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);

		int i = 0;
		for (i = 0; i < strlen; i++) {
			c = str.charAt(i);
			if (!((c >= 0x0001) && (c <= 0x007F)))
				break;
			bytearr[count++] = (byte) c;
		}

		for (; i < strlen; i++) {
			c = str.charAt(i);
			if ((c >= 0x0001) && (c <= 0x007F)) {
				bytearr[count++] = (byte) c;

			} else if (c > 0x07FF) {
				bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
				bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
				bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
			} else {
				bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
				bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
			}
		}
		buffer.writeBytes(bytearr, 0, utflen + 2);
	}

	public int readInt() {
		return buffer.readInt();
	}

	public int readShort() {
		return buffer.readShort();
	}

	public int readByte() {
		return buffer.readByte();
	}

	public double readDouble() {

		return buffer.readDouble();
	}

	public float readFloat() {
		return buffer.readFloat();
	}

	public long readLong() {
		return buffer.readLong();
	}

	public String readString() throws UTFDataFormatException {
		int utflen = buffer.readUnsignedShort();
		byte[] bytearr = null;
		char[] chararr = null;
		bytearr = new byte[utflen];
		chararr = new char[utflen];
		int c, char2, char3;
		int count = 0;
		int chararr_count = 0;

		buffer.readBytes(bytearr, 0, utflen);

		while (count < utflen) {
			c = (int) bytearr[count] & 0xff;
			if (c > 127)
				break;
			count++;
			chararr[chararr_count++] = (char) c;
		}

		while (count < utflen) {
			c = (int) bytearr[count] & 0xff;
			switch (c >> 4) {
			case 0:
			case 1:
			case 2:
			case 3:
			case 4:
			case 5:
			case 6:
			case 7:
				/* 0xxxxxxx */
				count++;
				chararr[chararr_count++] = (char) c;
				break;
			case 12:
			case 13:
				/* 110x xxxx 10xx xxxx */
				count += 2;
				if (count > utflen)
					throw new UTFDataFormatException("malformed input: partial character at end");
				char2 = (int) bytearr[count - 1];
				if ((char2 & 0xC0) != 0x80)
					throw new UTFDataFormatException("malformed input around byte " + count);
				chararr[chararr_count++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
				break;
			case 14:
				/* 1110 xxxx 10xx xxxx 10xx xxxx */
				count += 3;
				if (count > utflen)
					throw new UTFDataFormatException("malformed input: partial character at end");
				char2 = (int) bytearr[count - 2];
				char3 = (int) bytearr[count - 1];
				if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
					throw new UTFDataFormatException("malformed input around byte " + (count - 1));
				chararr[chararr_count++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
				break;
			default:
				/* 10xx xxxx, 1111 xxxx */
				throw new UTFDataFormatException("malformed input around byte " + count);
			}
		}
		// The number of chars produced may be less than utflen
		return new String(chararr, 0, chararr_count);
	}

	public void sendToSceneServer() {
		buffer.writeInt(sessionId);
		int length = this.buffer.readableBytes();

		ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(length + 4);
		buf.writeShort(127);
		buf.writeShort(length);
		buf.writeBytes(buffer, 0, length);
		buffer.release();
		this.buffer = buf;
		if (Dispatcher.sceneServerSession != null) {
			Dispatcher.sceneServerSession.writeAndFlush(buf);
		}else{
			buf.release();
		}
	}

}
